import * as bcrypt from "bcryptjs";

/**
 * bcrypt 工具类
 * @tutorial bcrypt 用于哈希化密码，区别于加密密码，哈希化后的密码无法被解密，只能通过比较哈希后的密码来验证密码是否正确。
 * 加密是通过加密算法将明文密码转换为不可读的密文，加密是双向函数，加密的内容可以用适当的密钥解密。
 * @class
 */
export class BcryptUtils {
    /**
     * 哈希密码（自动生成盐）
     * @param password 明文密码
     * @param rounds 盐轮数，默认为 10
     * @returns 哈希后的密码
     */
    static async hashPassword(password: string, rounds: number = 10): Promise<string> {
        return bcrypt.hash(password, rounds);
    }

    /**
     * 验证密码
     * @param password 明文密码
     * @param hash 哈希后的密码
     * @returns 是否匹配
     */
    static async comparePassword(password: string, hash: string): Promise<boolean> {
        return bcrypt.compare(password, hash);
    }

    /**
     * 更新哈希（如果旧哈希的轮数不足）
     * @param password 明文密码
     * @param hash 旧哈希值
     * @param newRounds 新轮数，默认为 10
     * @returns 新哈希值或 null
     */
    static async updateHash(password: string, hash: string, newRounds: number = 10): Promise<string | null> {
        const currentRounds = this.getRoundsFromHash(hash);
        if (currentRounds < newRounds) {
            return this.hashPassword(password, newRounds);
        }
        return null;
    }

    /**
     * 从哈希中提取盐轮数
     */
    private static getRoundsFromHash(hash: string): number {
        const parts = hash.split("$");
        return parseInt(parts[3] || "10"); // bcrypt 哈希格式: $2a$10$...salt...hash...
    }

    /**
     * 检查密码强度
     * @param {string} password 明文密码
     * @returns {number} 密码强度等级 1-4 (弱、一般、中等、强)
     */
    static checkPasswordStrength(password: string): number {
        const PasswordStrength = {
            Weak: 1,
            Normal: 2,
            Medium: 3,
            Strong: 4
        } as const;

        // 这里可以添加更复杂的密码强度检查逻辑
        const hasUppercase = /[A-Z]/.test(password);
        const hasLowercase = /[a-z]/.test(password);
        const hasDigit = /\d/.test(password);
        const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
        const isLongEnough = password.length >= 8;

        const conditionsMet = [hasUppercase, hasLowercase, hasDigit, hasSpecialChar, isLongEnough].filter(
            Boolean
        ).length;

        // 测试结果一个 true：弱 1，两个 true：一般 2，三-四个 true：中等 3，全部 true：强 4
        switch (conditionsMet) {
            case 1:
                return PasswordStrength.Weak;
            case 2:
                return PasswordStrength.Normal;
            case 3:
            case 4:
                return PasswordStrength.Medium;
            case 5:
                return PasswordStrength.Strong;
            default:
                return PasswordStrength.Weak; // 默认情况下返回弱等级 1
        }
    }
}
